home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-10-17 | 56.1 KB | 2,228 lines |
- Newsgroups: comp.sources.misc
- From: byron@archone.tamu.edu (Byron Rakitzis)
- Subject: v23i061: rc - A Plan 9 shell reimplementation, v1.2, Part01/06
- Message-ID: <csm-v23i061=rc.224128@sparky.IMD.Sterling.COM>
- X-Md4-Signature: a932f2a89d57b43a6a733a0325e502dd
- Date: Fri, 18 Oct 1991 03:42:31 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: byron@archone.tamu.edu (Byron Rakitzis)
- Posting-number: Volume 23, Issue 61
- Archive-name: rc/part01
- Environment: UNIX
- Supersedes: rc: Volume 20, Issue 10-13
-
- This is version 1.2 of the rc shell. rc is a command interpreter
- and programming language similar to sh(1). It is based on the
- AT&T plan 9 shell of the same name. The shell offers a C-like
- syntax (much more so than the C shell), and a powerful mechanism
- for manipulating variables. It is reasonably small and reasonably
- fast, especially when compared to contemporary shells. Its use is
- intended to be interactive, but the language lends itself well
- to scripts.
-
- There's a mailing list for rc at rc@archone.tamu.edu. Send requests
- to be added, etc. to rc-request@archone.tamu.edu.
-
- Byron Rakitzis
- --------------
- #!/bin/sh
- # This is a shell archive (produced by shar 3.49)
- # To extract the files from this archive, save it to a file, remove
- # everything above the "!/bin/sh" line above, and type "sh file_name".
- #
- # existing files will NOT be overwritten unless -c is specified
- #
- # This is part 1 of a multipart archive
- # do not concatenate these parts, unpack them in order with /bin/sh
- #
- # This shar contains:
- # length mode name
- # ------ ---------- ------------------------------------------
- # 7545 -rw-r--r-- CHANGES
- # 1106 -rw-r--r-- COPYRIGHT
- # 5050 -rw-r--r-- EXAMPLES
- # 3536 -rw-r--r-- Makefile
- # 3366 -rw-r--r-- README
- # 408 -rw-r--r-- addon.c
- # 1101 -rw-r--r-- addon.h
- # 11200 -rw-r--r-- builtins.c
- # 191 -rw-r--r-- builtins.h
- # 5252 -rw-r--r-- cfix.awk
- # 546 -rw-r--r-- config.h
- # 2339 -rw-r--r-- except.c
- # 310 -rw-r--r-- except.h
- # 2671 -rw-r--r-- exec.c
- # 104 -rw-r--r-- exec.h
- # 2017 -rw-r--r-- execve.c
- # 5485 -rw-r--r-- fn.c
- # 9420 -rw-r--r-- footobar.c
- # 258 -rw-r--r-- footobar.h
- # 1619 -rw-r--r-- getopt.c
- # 98 -rw-r--r-- getopt.h
- # 6378 -rw-r--r-- glob.c
- # 66 -rw-r--r-- glob.h
- # 9512 -rw-r--r-- glom.c
- # 322 -rw-r--r-- glom.h
- # 6760 -rw-r--r-- hash.c
- # 1313 -rw-r--r-- hash.h
- # 3622 -rw-r--r-- heredoc.c
- # 97 -rw-r--r-- heredoc.h
- # 714 -rw-r--r-- hfix.awk
- # 4951 -rw-r--r-- history.1
- # 6420 -rw-r--r-- history.c
- # 7405 -rw-r--r-- input.c
- # 373 -rw-r--r-- input.h
- # 209 -rw-r--r-- jbwrap.h
- # 10411 -rw-r--r-- lex.c
- # 476 -rw-r--r-- lex.h
- # 984 -rw-r--r-- list.c
- # 119 -rw-r--r-- list.h
- # 2703 -rw-r--r-- main.c
- # 1992 -rw-r--r-- match.c
- # 46 -rw-r--r-- match.h
- # 1716 -rw-r--r-- mksignal
- # 2229 -rw-r--r-- nalloc.c
- # 323 -rw-r--r-- nalloc.h
- # 377 -rw-r--r-- node.h
- # 772 -rw-r--r-- open.c
- # 50 -rw-r--r-- open.h
- # 79 -rw-r--r-- parse.h
- # 5406 -rw-r--r-- parse.y
- # 67056 -rw-r--r-- plan9.ps
- # 35457 -rw-r--r-- rc.1
- # 654 -rw-r--r-- rc.h
- # 2480 -rw-r--r-- redir.c
- # 28 -rw-r--r-- redir.h
- # 3078 -rw-r--r-- status.c
- # 239 -rw-r--r-- status.h
- # 766 -rw-r--r-- stddef.h
- # 462 -rw-r--r-- stdlib.h
- # 516 -rw-r--r-- string.h
- # 4722 -rw-r--r-- tree.c
- # 132 -rw-r--r-- tree.h
- # 759 -rw-r--r-- unistd.h
- # 5782 -rw-r--r-- utils.c
- # 884 -rw-r--r-- utils.h
- # 6567 -rw-r--r-- var.c
- # 127 -rw-r--r-- version.c
- # 1660 -rw-r--r-- wait.c
- # 120 -rw-r--r-- wait.h
- # 8100 -rw-r--r-- walk.c
- # 59 -rw-r--r-- walk.h
- # 2816 -rw-r--r-- which.c
- #
- if test -r _shar_seq_.tmp; then
- echo 'Must unpack archives in sequence!'
- echo Please unpack part `cat _shar_seq_.tmp` next
- exit 1
- fi
- # ============= CHANGES ==============
- if test -f 'CHANGES' -a X"$1" != X"-c"; then
- echo 'x - skipping CHANGES (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting CHANGES (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'CHANGES' &&
- Changes since rc-1.0:
- X
- builtin now forces a path-search for non-builtin commands. e.g.,
- X
- X builtin ls
- X
- forces a path search for /bin/ls, rather than running a function called
- "ls".
- X
- A bug in the builtin wait was fixed.
- X
- The builtin whatis how takes a -s flag, for displaying available
- signals and their handlers, and also prints correct code for
- reinterpretation. (metacharacters inside variable names were not
- correctly quoted)
- X
- An extra field was added to the "limit" builtin for SunOS systems,
- which apparently allow a limit on file descriptors.
- X
- A home-rolled execve() was written for people with geriatric unices
- that don't do #! in the kernel.
- X
- SIGTERM is now ignored by rc along with SIGQUIT. (This is not how
- Duff's shell behaves, but it is standard practise for Unix shells to
- ignore SIGTERM)
- X
- If $history was set to a bad file, then rc would print far too many
- error messages. Now rc prints one error message and assigns null to
- $history, if $history names an invalid file.
- X
- rc now explicitly refuses to trap SIGCLD on System V machines, because
- of the weird way in which SIGCLD work. (really because I didn't want to
- get into the job control business)
- X
- A bug was fixed in the parser so that functions with metacharacters in
- their names are correctly imported from the environment.
- X
- he globber was changed to call stat() before calling opendir();
- apparently opendir() succeeds on some Unices even when invoked on
- regular files.
- X
- It is now illegal to have '=' be part of a variable name. This should
- be the only illegal character inside a variable name!
- X
- backquote rescanning was rewritten from scratch; now it no longer
- assigns null list entries to represent consecutive occurences of $ifs
- characters in the input.
- X
- e.g., now `{echo ' '} returns a null list, and not a 4-element list
- of null characters.
- X
- rc used to export all handlers but those in {sighup, sigint, sigquit,
- sigterm, sigexit}. Now rc does not export ANY signal handlers.
- X
- rc's lexer was cleaned up to accept 8-bit data. rc is now presumed to
- be 8-bit clean. I would like to hear of evidence to the contrary.
- X
- rc now traps EOF when scanning a variable name inside a heredoc.
- X
- rc's fdgchar() was cleaned up so that it did not assign negative values
- to unsigned objects. (this one is truly for the pedants)
- X
- rc's lexer was fixed so that multiple backslashes at the end of a line
- are interpreted correctly.
- X
- rc's parser now allows a newline to appear after "else" (via
- skipnl()).
- X
- main() was exiting in certain situations with an exit status of 0
- instead of rc's real exit status.
- X
- rc's yacc file was fixed so that yaccs which do "magic" can clean up
- after themselves via the tokens YYACCEPT and YYABORT. Most notably,
- Sun's yyparse() calls malloc.
- X
- A mistake in the argument list of treecpy() was cleaned up.
- X
- Calls to write() are now checked for failure.
- X
- walk() was optimized for space in two ways: rPIPE was removed and
- placed in a separate function body, and a few obvious chances for
- employing tail-recursion via goto's was taken. This should result in a
- slightly smaller use of stackspace.
- X
- Additions since 1.1beta:
- ------------------------
- X
- John Mackin kindly supplied a set of awk scripts to convert rc's
- source into K&R 1 C. To perform the conversion, type "make C".
- X
- Paul Haahr and I wrote a history program loosely based upon one
- that Boyd Roberts sent to me. Both of these programs are
- reimplementations of v8 shell history. Type "make history".
- X
- Tom Duff has kindly given permission for his paper "rc - a Shell
- for Plan 9 and UNIX Systems" to be distributed in PostScript form
- with my rc. The file is called "plan9-rc.ps".
- X
- Changes since 1.1beta:
- ----------------------
- X
- Builtins were changed to flag an error on too many arguments.
- Also, the shift builtin now complains if there are no more elements
- in $* to shift.
- X
- The error message printed by exec() ("foo not found") when it could
- not find an executable has been updated to read "Permission denied",
- and so on.
- X
- Bugs in the home-rolled execve() were fixed.
- X
- A compile-time option was added to rc so that rc exports environment
- variable names using only the character set [a-zA-Z0-9_]. This is for
- braindamaged Bourne shells which don't like characters like - or :
- appearing in variable names. rc does this by encoding the variable
- name in a hex-based code. It seems to work fine on systems which need
- it, but it's definitely a hack.
- X
- rc now supports /dev/fd, if you have it.
- X
- Occasionally rc would be too overzealous in its reporting of errors,
- so a failed call to write() would cause another failed call to
- write() (to print the error!!) and so on... Now rc no longer reports
- failed calls to write().
- Changes since 1.1gamma:
- X
- rc sorts the environment strings before exporting them
- X
- rc ignores signals on rc -c. Fixes the "rc -c sh" followed by an
- interrupt bug.
- X
- the bogus skipnl() action is gone from the parser; the optional
- newlines are implemented as yacc productions.
- X
- a bug in the function-printing code was fixed ( {echo}>file was
- exported incorrectly as {echo}>file () ).
- X
- a=1 {b=2} is now correctly executed as a local assignment to a and a
- global assignemnt to b, at the cost of a few extra braces in the
- printing of functions.
- X
- rc's use of jmp_buf was changed to work with braindamaged architectures
- which don't define jmp_buf as an array.
- X
- rc's access() was broken when uid == 0.
- X
- rc now incorporates switch--case parsing in the grammar; this means
- that the rules are a little more strict than they were before, but
- reasonable switch() statements should not break.
- X
- rc -n means don't execute commands, just parse.
- X
- eval statements now do not reset the line number count in scripts. This
- allows for more useful error messages, e.g.,
- X
- X line 53: syntax error near end of line
- X
- as opposed to
- X
- X line 1: syntax error near end of line
- X
- rc's non-exporting of variables like "pid" and "*" has been improved;
- it was previously not possible to export a function named "pid" or a
- variable named "sigint". This has been fixed.
- X
- rc's use of wait() was completely revamped. Now FIFOs should be more
- reliable, as should be signal handlers.
- X
- rc -x is now more informative: variable and function assignments are
- printed, as are calls to ~.
- X
- rc -nx now prints the parsetree of each command in addition to refusing
- to execute it.
- X
- for all it's worth, variables named "while" "switch" etc. are now
- correctly described by "whatis" (i.e., quoted).
- X
- for all it's worth, you can now return lists from functions, as long as
- each element is a valid exit status (integer, or lowercase signal name
- (with or without +core)) The most useful application for this would
- be:
- X
- X fn foo {
- X stuff
- X stat = $status
- X stuff
- X return $stat
- X }
- X
- here documents in loops and/or functions now interpret variable
- expansions at execute rather than at parse-time.
- X
- Changes since 1.1gamma:
- -----------------------
- X
- Several bugs were fixed. In particular:
- X
- When an exception in a braced group occurred, rc did not pop all local
- variable definitions.
- X
- returning from fn prompt would cause an infinite loop.
- X
- the postfix increment operator used for numbering the /tmp fifos that
- rc uses to implement <{} redirection was placed inside a cpp macro
- which evaluated an argument twice, and hence all fifos were named after
- odd integers. In the interest of fairness to the even integers, this
- has been corrected.
- X
- the man page has been cleaned up in countless ways.
- X
- rc -nx printed a redundant file-descriptor for "foo<{bar}"
- X
- "builtin exec sh" did not do the right thing, partly because exec is
- not a genuine builtin. However, now it does.
- SHAR_EOF
- chmod 0644 CHANGES ||
- echo 'restore of CHANGES failed'
- Wc_c="`wc -c < 'CHANGES'`"
- test 7545 -eq "$Wc_c" ||
- echo 'CHANGES: original size 7545, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= COPYRIGHT ==============
- if test -f 'COPYRIGHT' -a X"$1" != X"-c"; then
- echo 'x - skipping COPYRIGHT (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting COPYRIGHT (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'COPYRIGHT' &&
- /*
- X * Copyright 1991 Byron Rakitzis. All rights reserved.
- X *
- X * This software is not subject to any license of the American Telephone
- X * and Telegraph Company or of the Regents of the University of California.
- X *
- X * Permission is granted to anyone to use this software for any purpose on
- X * any computer system, and to alter it and redistribute it freely, subject
- X * to the following restrictions:
- X *
- X * 1. The author is not responsible for the consequences of use of this
- X * software, no matter how awful, even if they arise from flaws in it.
- X *
- X * 2. The origin of this software must not be misrepresented, either by
- X * explicit claim or by omission. Since few users ever read sources,
- X * credits must appear in the documentation.
- X *
- X * 3. Altered versions must be plainly marked as such, and must not be
- X * misrepresented as being the original software. Since few users
- X * ever read sources, credits must appear in the documentation.
- X *
- X * 4. This notice may not be removed or altered.
- X *
- X * [this copyright notice is adapted from Henry Spencer's
- X * "awf" copyright notice.]
- X */
- SHAR_EOF
- chmod 0644 COPYRIGHT ||
- echo 'restore of COPYRIGHT failed'
- Wc_c="`wc -c < 'COPYRIGHT'`"
- test 1106 -eq "$Wc_c" ||
- echo 'COPYRIGHT: original size 1106, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= EXAMPLES ==============
- if test -f 'EXAMPLES' -a X"$1" != X"-c"; then
- echo 'x - skipping EXAMPLES (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting EXAMPLES (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'EXAMPLES' &&
- There is no repository for useful rc code snippets as yet, so I'm including
- a (short) file in the distribution with some helpful/intriguing pieces of
- rc code.
- X
- A sample .rcrc
- --------------
- Here is the .rcrc I use on archone:
- X
- umask 022
- path=(/bin /usr/bin /usr/ucb)
- ht=`/usr/arch/bin/hosttype
- h=$home
- history=$h/.history
- bin=$h/bin/$ht
- lib=$h/lib/$ht
- sh=$h/bin/sh
- include=$h/lib/include
- X
- switch ($ht) {
- case sun*
- X OBERON='. '$h/other/oberon
- X p=/usr/ucb
- X compiler='gcc -Wall -O -g'
- X MANPATH=$h/man:/usr/arch/man:/usr/man
- X if (! ~ $TERM ()) {
- X stty dec
- X /usr/arch/bin/msgs -q
- X }
- case next
- X p=(/usr/ucb /usr/bin /NextApps)
- X compiler='cc -Wall -O -g -DNODIRENT'
- X MANPATH=$h/man:/usr/arch/man:/usr/man
- X if (! ~ $TERM ())
- X stty dec
- case sgi
- X p=(/usr/ucb /usr/sbin /usr/bin)
- X compiler='gcc -Wall -O -g -DNOSIGCLD'
- X MANPATH=$h/man:/usr/arch/man:/usr/catman
- X if (!{~ $TERM () || ~ $TERM *iris*})
- X stty line 1 intr '' erase '' kill ''
- case *
- X echo .rcrc not configured for this machine
- }
- X
- path=(. $sh $bin /usr/arch/bin $p /bin /usr/bin/X11 /etc /usr/etc)
- cdpath=(. .. $h $h/src $h/misc $h/other $h/adm)
- RNINIT=-d$h' -t -M -2400-h -2400+hfrom'; DOTDIR=$h/misc/news
- PRINTER=lw
- X
- fn s {
- X echo $status
- }
- fn cd {
- X builtin cd $1 && \
- X switch ($1) {
- X case ()
- X dir=$home
- X case *
- X dir=()
- X }
- }
- fn pwd {
- X if (~ $dir ())
- X dir=`/bin/pwd
- X echo $dir
- }
- fn x {
- X if (~ `tty /dev/console)
- X clear_colormap
- X clear
- X exit
- }
- fn p {
- X if (~ $history ()) {
- X echo '$history not set' >[1=2]
- X return 1
- X }
- X
- X if (! ~ $#* 0 1 2) {
- X echo usage: $0 '[egrep pattern] [sed command]' >[1=2]
- X return 1
- X }
- X
- X command=`{
- X egrep -v '^[ ]*p([ ]+|$)' $history | switch ($#*) {
- X case 0
- X cat
- X case 1
- X egrep $1
- X case 2
- X egrep $1 | sed $2
- X } | tail -1
- X }
- X
- X echo $command
- X eval $command
- }
- X
- if (~ $TERM dialup network) {
- X TERM=vt100
- X biff y
- }
- X
- A front-end to NeXT's "openfile"
- --------------------------------
- X
- Named after the sam "B" command for opening a file, this script was written
- by Paul Haahr. (Assumes the "pick" command from Kernighan and Pike is also
- in your path.)
- X
- #!/bin/rc
- if (~ $#* 0)
- X exec openfile
- create = ()
- files = ()
- for (i in $*)
- X if (test -f $i) {
- X files = ($files $i)
- X } else {
- X create = ($create $i)
- X }
- create = `{ pick $create }
- files = ($files $create)
- for (i in $create)
- X > $i
- if (! ~ $#files 0)
- X openfile $files
- X
- A read function
- ---------------
- X
- Unlike sh, rc doesn't have a read. This clever alternative returns an
- exit status as well as fetch a variable. Use as
- X
- X read foo
- X
- to set $foo to a single line from the terminal.
- X
- (due to John Mackin <john@syd.dit.csiro.au>)
- X
- fn read {
- X x=() {
- X x = `` ($nl) { awk '{print; print 0; exit}' ^ $nl ^ \
- X 'END {print 1; print 1}' }
- X $1 = $x(1)
- X return $x(2)
- X }
- }
- X
- XFrom cs.wisc.edu!dws Fri Aug 2 18:16:14 1991
- X
- #-------
- # ls front end
- #-------
- fn ls \
- {
- X test -t 1 && * = (-FCb $*)
- X builtin ls $*
- }
- #-------
- # nl - holds a newline, useful in certain command substitutions
- #-------
- nl='
- '
- #-------
- # show - tell me about a name
- #
- # Runs possibly dangerous things through cat -v in order to protect
- # me from the effects of control characters I might have in the
- # environment.
- #-------
- fn show \
- {
- X * = `` $nl {whatis -- $*}
- X for(itis)
- X {
- X switch($^itis)
- X {
- X case 'fn '* ; echo $itis | cat -v -t
- X case builtin* ; echo $itis
- X case /* ; file $itis; ls -ld $itis
- X case *'='* ; echo $itis | cat -v -t
- X case * ; echo $itis: UNKNOWN: update show
- X }
- X }
- X itis = ()
- }
- #-------
- # Tell me automatically when a command has a nonzero status.
- #-------
- fn prompt \
- {
- X Status = $status
- X ~ $Status 0 || echo '[status '$Status']'
- }
- X
- #-------
- # chop - echo the given list, less its final member
- #
- # e.g. chop (a b c) -> (a b)
- #-------
- fn chop {
- X ~ $#* 0 1 && return 0
- X ans = '' { # local variable
- X ans = ()
- X while(! ~ $#* 1)
- X {
- X ans = ($ans $1)
- X shift
- X }
- X echo $ans
- X }
- }
- X
- XFrom arnold@audiofax.com Thu May 30 08:49:51 1991
- X
- # cd.rc --- souped up version of cd
- X
- # this is designed to emulate the fancy version of cd in ksh,
- # so if you're a purist, feel free to gag
- X
- _cwd=$home
- _oldcwd=$home
- X
- fn cd {
- X if (~ $#* 0) {
- X if (~ $_cwd $home) { # do nothing
- X } else {
- X builtin cd && { _oldcwd=$_cwd ; _cwd=$home }
- X }
- X } else if (~ $#* 1) {
- X if (~ $1 -) {
- X _t=$_cwd
- X builtin cd $_oldcwd && {
- X _cwd=$_oldcwd
- X _oldcwd=$_t
- X echo $_cwd
- X }
- X _t=()
- X } else {
- X # if a cd happens through the cdpath, rc echos
- X # the directory on its own. all we have to do
- X # is track where we end up
- X _dopwd = 1
- X { ~ $1 /* } && _dopwd = 0 # absolute path
- X builtin cd $1 && {
- X _oldcwd=$_cwd
- X _cwd=$1
- X { ~ $_dopwd 1 } && _cwd=`/bin/pwd
- X }
- X _dopwd=()
- X }
- X } else if (~ $#* 2) {
- X _t=`{ echo $_cwd | sed 's<'$1'<'$2'<' }
- X builtin cd $_t && {
- X _oldcwd=$_cwd
- X _cwd=$_t
- X echo $_cwd
- X }
- X _t=()
- X } else {
- X echo cd: takes 0, 1, or 2 arguments >[1=2]
- X builtin cd $1 && { _oldcwd=$_cwd ; _cwd=`/bin/pwd ; echo $_cwd }
- X }
- }
- X
- fn pwd { echo $_cwd }
- X
- SHAR_EOF
- chmod 0644 EXAMPLES ||
- echo 'restore of EXAMPLES failed'
- Wc_c="`wc -c < 'EXAMPLES'`"
- test 5050 -eq "$Wc_c" ||
- echo 'EXAMPLES: original size 5050, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= Makefile ==============
- if test -f 'Makefile' -a X"$1" != X"-c"; then
- echo 'x - skipping Makefile (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting Makefile (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
- # Makefile for rc.
- X
- # Check the definitions in stddef.h and the configuration parameters below
- # to make sure they are correct for your system.
- X
- # Configuration parameters for rc:
- #
- # Configurations may be added or deleted using ed; e.g., the ed command
- # for adding the NODIRENT configuration would be
- #
- # /#NODIRENT/s/^.//
- #
- # Note that config.h automatically sets up configurations for some
- # systems.
- X
- # Define the macro NODIRENT if your system has <sys/dir.h> but not
- # <dirent.h>. (e.g., NeXT-OS)
- #NODIRENT = -DNODIRENT
- X
- # Define the macro DEVFD if your system supports /dev/fd.
- #DEVFD = -DDEVFD
- X
- # Define the macro NOLIMITS if your system does not support Berkeley
- # limits.
- #NOLIMITS = -DNOLIMITS
- X
- # Define the macro NOSIGCLD if your system uses SIGCLD in the System
- # V way. (e.g., Irix)
- #NOSIGCLD = -DNOSIGCLD
- X
- # Define the macro READLINE if you want rc to call GNU readline
- # instead of read(2) on interactive shells.
- #READLINE = -DREADLINE
- X
- # Define the macro NOEXECVE if your Unix does not interpret #! in the
- # kernel, and set EXECVE to execve.o.
- #NOEXECVE = -DNOEXECVE
- #EXECVE = execve.o
- X
- # Define the macro ADDON if you wish to extend rc via locally-defined
- # builtins. An interface is provided in addon.[ch]. Note that the author
- # does not endorse any such extensions, rather hopes that this way
- # rc will become useful to more people.
- #ADDON = addon.o
- X
- # If you want rc to default to some interpreter for files which don't
- # have a legal #! on the first line, define the macro DEFAULTINTERP.
- #DEFAULTINTERP = -DDEFAULTINTERP=\"/bin/sh\"
- X
- # If your /bin/sh (or another program you care about) rejects
- # environment variables with special characters in them, rc can put
- # out ugly variable names using [_0-9a-zA-Z] that encode the real
- # name; define PROTECT_ENV for this hack.
- #PROTECT_ENV = -DPROTECT_ENV
- X
- # If your window system has a broken terminal emulator (and I'm talking
- # specifically about the NeXT here) which expects your shell to do csh-
- # like job control stuff on startup, define PROTECT_JOB so that rc can
- # do the "right" thing.
- #PROTECT_JOB = -DPROTECT_JOB
- X
- CONFIG = $(NODIRENT) $(NOCMDARG) $(DEVFD) $(NOLIMITS) $(NOSIGCLD) \
- X $(READLINE) $(NOEXECVE) $(DEFAULTINTERP) $(PROTECT_ENV) $(PROTECT_JOB)
- X
- # Use an ANSI compiler (or at least one that groks prototypes and void *):
- CC=gcc -g -O
- CFLAGS=$(CONFIG)
- LDFLAGS=
- X
- # Use bison if you will, but yacc generates a smaller y.tab.c, and the speed
- # of the parser is largely irrelevant in a shell.
- YACC=yacc
- X
- OBJS = $(ADDON) builtins.o except.o exec.o $(EXECVE) fn.o footobar.o getopt.o \
- X glob.o glom.o hash.o heredoc.o input.o lex.o list.o main.o match.o \
- X nalloc.o open.o redir.o sigmsgs.o status.o tree.o utils.o var.o \
- X version.o wait.o walk.o which.o y.tab.o
- X
- # If rc is compiled with GNU readline, you must supply the correct arguments to
- # ld on this line. Typically this would be something like:
- #
- # $(CC) -o rc $(OBJS) -lreadline -ltermcap
- X
- rc: $(OBJS)
- X $(CC) -o rc $(OBJS)
- X
- sigmsgs.c: mksignal
- X sh mksignal /usr/include/sys/signal.h
- X
- y.tab.c: parse.y
- X $(YACC) -d parse.y
- X
- clean:
- X rm -f a.* *.o *.s core *.tab.* *.out
- X
- history: history.c
- X $(CC) -o ./- history.c
- X rm -f ./-- ./-p ./--p
- X ln -s ./- ./--
- X ln -s ./- ./-p
- X ln -s ./- ./--p
- X
- C: force
- X -mkdir C
- X for i in *.c; do awk -f cfix.awk $$i >C/$$i; done
- X for i in *.h; do awk -f hfix.awk $$i >C/$$i; done
- X sed 's/CFLAGS=/&-Dconst= /' Makefile > C/Makefile
- X cp mksignal *.y C
- X
- force:
- X
- # dependencies:
- X
- sigmsgs.h: sigmsgs.c
- lex.o y.tab.o: y.tab.c
- builtins.c fn.c status.c hash.c: sigmsgs.h
- SHAR_EOF
- chmod 0644 Makefile ||
- echo 'restore of Makefile failed'
- Wc_c="`wc -c < 'Makefile'`"
- test 3536 -eq "$Wc_c" ||
- echo 'Makefile: original size 3536, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= README ==============
- if test -f 'README' -a X"$1" != X"-c"; then
- echo 'x - skipping README (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting README (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'README' &&
- This is release 1.2 of rc.
- X
- Read COPYRIGHT for copying information. All files are
- X
- Copyright 1991, Byron Rakitzis.
- X
- COMPILING
- X
- rc was written in portable ANSI C. For those without gcc or some other
- compiler which groks prototypes and (void *), there is a set of awk
- scripts which convert the source into old-style C. To do this, type
- "make C". This is a nondestructive operation; the new code will be
- placed in a subdirectory called "C".
- X
- Please read the Makefile, and make sure that the configuration parameters
- are appropriate for your system. Also, look at config.h and stddef.h.
- X
- To compile the history program, type "make history". This will create
- 1 binary and three soft links pointing at the binary. They are respectively
- named -, --, -p and --p.
- X
- BUGS
- X
- Send bug reports to byron@archone.tamu.edu. If a core dump is
- generated, sending me a backtrace will help me out a great deal. You
- can get a backtrace like this:
- X
- X ; gdb rc core
- X (gdb) where
- X <<<BACKTRACE INFO>>>
- X (gdb)
- X
- Also, always report the machine, compiler and OS used to make rc. It's
- possible I may have access to a machine of that type, in which case it
- becomes much easier for me to track the bug down.
- X
- If you are using gcc, please make sure that you have a recent version of
- the compiler (1.39 and up) before you send me a note; I have found that
- older versions of gcc choke over rc and generate bad code on several
- architectures.
- X
- MAN PAGE
- X
- The man page works with nroff on my Sun, but I had to use groff in
- order to get the man page typeset for a laser printer. I am assuming
- that ditroff will also format rc.1 correctly for a printer. If anyone
- can tell me how to get BSD troff to do this, I would be grateful.
- X
- FEEPING CREATURISM
- X
- See the end of the man page, under "INCOMPATABILITIES" for (known?)
- differences from the "real" rc. Most of these changes were necessary
- to get rc to work in a reasonable fashion on a real UNIX system; a
- few were changes motivated by concern about some inadequacies in
- the original design.
- X
- CREDITS
- X
- This shell was written by me, Byron Rakitzis, but kudos go to Paul
- Haahr for letting me know what a shell should do and for contributing
- certain bits and pieces to rc (notably the limits code, most of which.c
- and the backquote redirection code), and to Hugh Redelmeier for running
- rc through his fussy ANSI compiler and thereby provoking interesting
- discussions about portability, and also for providing many valuable
- suggestions for improving rc's code in general. Finally, many thanks
- go to David Sanderson, for reworking the man page to format well with
- troff, and for providing many suggestions both for rc and its man page.
- X
- Thanks to Boyd Roberts for the original history.c, and to Hugh again
- for re-working parts of that code.
- X
- Of course, without Tom Duff's design of the original rc, I could not
- have written this shell (though I probably would have written *a*
- shell). Almost of all of the features, with minor exceptions, have been
- implemented as described in the Unix v10 manuals. Hats off to td for
- designing a C-like, minimal but very useful shell.
- X
- Tom Duff has kindly given permission for the paper he wrote for UKUUG
- to be distributed with this version of rc (called "plan9.ps"). Please
- read this paper bearing in mind that it describes a program that was
- written at AT&T and that the version of rc presented here differs in some
- respects.
- SHAR_EOF
- chmod 0644 README ||
- echo 'restore of README failed'
- Wc_c="`wc -c < 'README'`"
- test 3366 -eq "$Wc_c" ||
- echo 'README: original size 3366, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= addon.c ==============
- if test -f 'addon.c' -a X"$1" != X"-c"; then
- echo 'x - skipping addon.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting addon.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'addon.c' &&
- /*
- X This file contains the implementations of any locally defined
- X builtins.
- */
- X
- #ifdef DWS
- X
- /*
- X This is what DaviD Sanderson (dws@cs.wisc.edu) uses.
- */
- X
- #include <sys/types.h>
- #include <sys/file.h>
- #include <sys/stat.h>
- X
- #include "rc.h" /* for boolean TRUE, FALSE */
- #include "status.h" /* for set() */
- #include "addon.h"
- #include "utils.h"
- X
- #include "addon/access.c"
- #include "addon/test.c"
- X
- #endif
- SHAR_EOF
- chmod 0644 addon.c ||
- echo 'restore of addon.c failed'
- Wc_c="`wc -c < 'addon.c'`"
- test 408 -eq "$Wc_c" ||
- echo 'addon.c: original size 408, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= addon.h ==============
- if test -f 'addon.h' -a X"$1" != X"-c"; then
- echo 'x - skipping addon.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting addon.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'addon.h' &&
- /*
- X This file is the interface to the rest of rc for any locally
- X defined addon builtins. By default there are none.
- X The interface consists of the following macros.
- X
- X ADDON_FUN A comma-separated list of the function names for the
- X builtins.
- X
- X ADDON_STR A comma-separated list of string literals corresponding
- X to the function names in ADDON_FUN.
- X
- X The addon functions must also have proper prototypes in this file.
- X The builtins all have the form:
- X
- X void b_NAME(char **av);
- X
- X Builtins report their exit status using set(TRUE) or set(FALSE).
- X
- X Example:
- X
- X #define ADDON_FUN b_test, b_printf
- X #define ADDON_STR "test", "printf"
- X extern void b_test(char **av);
- X extern void b_printf(char **av);
- */
- X
- #define ADDON_FUN /* no addons by default */
- #define ADDON_STR /* no addons by default */
- X
- #ifdef DWS
- X
- /*
- X This is what DaviD Sanderson (dws@cs.wisc.edu) uses.
- */
- X
- #undef ADDON_FUN
- #define ADDON_FUN b_access, b_test, b_test
- #undef ADDON_STR
- #define ADDON_STR "access", "test", "["
- X
- extern void b_access(char **av);
- extern void b_test(char **av);
- X
- #endif
- SHAR_EOF
- chmod 0644 addon.h ||
- echo 'restore of addon.h failed'
- Wc_c="`wc -c < 'addon.h'`"
- test 1101 -eq "$Wc_c" ||
- echo 'addon.h: original size 1101, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= builtins.c ==============
- if test -f 'builtins.c' -a X"$1" != X"-c"; then
- echo 'x - skipping builtins.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting builtins.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'builtins.c' &&
- /* builtins.c: the collection of rc's builtin commands */
- X
- /*
- X NOTE: rc's builtins do not call "rc_error" because they are
- X commands, and rc errors usually arise from syntax errors. e.g.,
- X you probably don't want interpretation of a shell script to stop
- X because of a bad umask.
- */
- X
- #include "jbwrap.h"
- #include <errno.h>
- #include "rc.h"
- #ifndef NOLIMITS
- #include <sys/time.h>
- #include <sys/resource.h>
- #endif
- #include "utils.h"
- #include "walk.h"
- #include "input.h"
- #include "builtins.h"
- #include "hash.h"
- #include "nalloc.h"
- #include "status.h"
- #include "footobar.h"
- #include "lex.h"
- #include "open.h"
- #include "except.h"
- #include "redir.h"
- #include "glom.h"
- #include "tree.h"
- #include "sigmsgs.h"
- #include "getopt.h"
- #include "wait.h"
- #include "addon.h"
- X
- extern int umask(int);
- X
- static void b_break(char **), b_cd(char **),
- X b_echo(char **), b_eval(char **), b_exit(char **), b_limit(char **),
- X b_return(char **), b_shift(char **), b_umask(char **), b_wait(char **),
- X b_whatis(char **);
- X
- static builtin_t *const builtins[] = {
- X b_break, b_builtin, b_cd, b_echo, b_eval, b_exec, b_exit,
- X b_limit, b_return, b_shift, b_umask, b_wait, b_whatis, b_dot,
- X ADDON_FUN
- };
- X
- static char *const builtins_str[] = {
- X "break", "builtin", "cd", "echo", "eval", "exec", "exit",
- X "limit", "return", "shift", "umask", "wait", "whatis", ".",
- X ADDON_STR
- };
- X
- builtin_t *isbuiltin(char *s) {
- X int i;
- X
- X for (i = 0; i < arraysize(builtins_str); i++)
- X if (streq(builtins_str[i], s))
- X return builtins[i];
- X return NULL;
- }
- X
- /* funcall() is the wrapper used to invoke shell functions. pushes $*, and "return" returns here. */
- X
- void funcall(char **av) {
- X jbwrap j;
- X Estack e1, e2;
- X
- X if (setjmp(j.j))
- X return;
- X
- X starassign(*av, av+1, TRUE);
- X except(RETURN, &j, &e1);
- X except(VARSTACK, "*", &e2);
- X walk(treecpy(fnlookup(*av),nalloc), TRUE);
- X varrm("*", TRUE);
- X unexcept(); /* VARSTACK */
- X unexcept(); /* RETURN */
- }
- X
- static void arg_count(char *name) {
- X fprint(2, "too many arguments to %s\n", name);
- X set(FALSE);
- }
- X
- static void badnum(char *num) {
- X fprint(2, "%s is a bad number", num);
- X set(FALSE);
- }
- X
- /* a dummy command. (exec() performs "exec" simply by not forking) */
- X
- void b_exec(char **av) {
- }
- X
- /* echo -n omits a newline. echo -- -n echos '-n' */
- X
- static void b_echo(char **av) {
- X SIZE_T i;
- X char *format = "%a\n";
- X
- X if (*++av != NULL) {
- X if (streq(*av, "-n")) {
- X format = "%a";
- X av++;
- X } else if (streq(*av, "--")) {
- X av++;
- X }
- X }
- X
- X i = strarraylen(av) + 1; /* one for the null terminator */
- X
- X if (i < FPRINT_SIZE)
- X fprint(1, format, av);
- X else
- X writeall(1, sprint(nalloc(i), format, av), i-1);
- X set(TRUE);
- }
- X
- /* cd. traverse $cdpath if the directory given is not an absolute pathname */
- X
- static void b_cd(char **av) {
- X List *s, nil;
- X char *path = NULL;
- X SIZE_T t, pathlen = 0;
- X
- X if (*++av == NULL) {
- X s = varlookup("home");
- X *av = (s == NULL) ? "/" : s->w;
- X } else if (av[1] != NULL) {
- X arg_count("cd");
- X return;
- X }
- X
- X if (isabsolute(*av)) { /* absolute pathname? */
- X if (chdir(*av) < 0) {
- X set(FALSE);
- X uerror(*av);
- X } else
- X set(TRUE);
- X } else {
- X s = varlookup("cdpath");
- X if (s == NULL) {
- X s = &nil;
- X nil.w = "";
- X nil.n = NULL;
- X }
- X do {
- X if (s != &nil && *s->w != '\0') {
- X t = strlen(*av) + strlen(s->w) + 2;
- X if (t > pathlen)
- X path = nalloc(pathlen = t);
- X strcpy(path, s->w);
- X strcat(path, "/");
- X strcat(path, *av);
- X } else {
- X pathlen = 0;
- X path = *av;
- X }
- X if (chdir(path) >= 0) {
- X set(TRUE);
- X if (interactive && *s->w != '\0' && !streq(s->w,"."))
- X fprint(1,"%s\n",path);
- X return;
- X }
- X s = s->n;
- X } while (s != NULL);
- X fprint(2,"couldn't cd to %s\n", *av);
- X set(FALSE);
- X }
- }
- X
- static void b_umask(char **av) {
- X int i;
- X
- X if (*++av == NULL) {
- X set(TRUE);
- X i = umask(0);
- X umask(i);
- X fprint(1, "0%o\n", i);
- X } else if (av[1] == NULL) {
- X i = o2u(*av);
- X if ((unsigned int) i > 0777) {
- X fprint(2,"bad umask\n");
- X set(FALSE);
- X } else {
- X umask(i);
- X set(TRUE);
- X }
- X } else {
- X arg_count("umask");
- X return;
- X }
- }
- X
- static void b_exit(char **av) {
- X int s;
- X
- X if (av[1] == NULL)
- X rc_exit(getstatus());
- X if (av[2] != NULL) {
- X fprint(2, "exit: too many arguments\n");
- X rc_exit(1);
- X }
- X if ((s = a2u(av[1])) >= 0)
- X rc_exit(s);
- X badnum(av[1]);
- X rc_exit(1);
- }
- X
- /* raise a "return" exception, i.e., return from a function. if an integer argument is present, set $status to it */
- X
- static void b_return(char **av) {
- X if (av[1] != NULL)
- X ssetstatus(av + 1);
- X rc_raise(RETURN);
- }
- X
- /* raise a "break" exception for breaking out of for and while loops */
- X
- static void b_break(char **av) {
- X if (av[1] != NULL) {
- X arg_count("break");
- X return;
- X }
- X rc_raise(BREAK);
- }
- X
- /* shift $* n places (default 1) */
- X
- static void b_shift(char **av) {
- X int shift;
- X List *s, *dollarzero;
- X
- X shift = (av[1] == NULL ? 1 : a2u(av[1]));
- X
- X if (av[1] != NULL && av[2] != NULL) {
- X arg_count("shift");
- X return;
- X }
- X
- X if (shift < 0) {
- X badnum(av[1]);
- X return;
- X }
- X
- X s = varlookup("*")->n;
- X dollarzero = varlookup("0");
- X
- X while (s != NULL && shift != 0) {
- X s = s->n;
- X --shift;
- X }
- X
- X if (s == NULL && shift != 0) {
- X fprint(2,"cannot shift\n");
- X set(FALSE);
- X } else {
- X varassign("*", append(dollarzero, s), FALSE);
- X set(TRUE);
- X }
- }
- X
- /* dud function */
- X
- void b_builtin(char **av) {
- }
- X
- /* wait for a given process, or all outstanding processes */
- X
- static void b_wait(char **av) {
- X int stat, pid;
- X
- X if (av[1] == NULL) {
- X waitforall(&stat);
- X setstatus(stat);
- X return;
- X }
- X
- X if (av[2] != NULL) {
- X arg_count("wait");
- X return;
- X }
- X
- X if ((pid = a2u(av[1])) < 0) {
- X badnum(av[1]);
- X return;
- X }
- X
- X if (rc_wait4(pid, &stat) > 0)
- X setstatus(stat);
- X else
- X set(FALSE);
- }
- X
- /*
- X whatis without arguments prints all variables and functions. Otherwise, check to see if a name
- X is defined as a variable, function or pathname.
- */
- X
- static void b_whatis(char **av) {
- X enum bool f,found;
- X int i,j,ac,c;
- X List *s;
- X Node *n;
- X char *e;
- X boolean ess = FALSE;
- X
- X optind = 0;
- X for (ac = 0; av[ac] != NULL; ac++)
- X ; /* count the arguments for getopt */
- X
- X while ((c = getopt(ac, av, "s")) != -1)
- X switch (c) {
- X case 's':
- X ess = TRUE;
- X break;
- X case '?':
- X set(FALSE);
- X return;
- X }
- X
- X av += optind;
- X
- X if (*av == NULL && !ess) {
- X whatare_all_vars();
- X set(TRUE);
- X return;
- X }
- X
- X if (ess)
- X whatare_all_signals();
- X
- X found = TRUE;
- X
- X for (i = 0; av[i] != NULL; i++) {
- X f = FALSE;
- X errno = ENOENT;
- X if ((s = varlookup(av[i])) != NULL) {
- X f = TRUE;
- X prettyprint_var(1, av[i], s);
- X }
- X if ((n = fnlookup(av[i])) != NULL) {
- X f = TRUE;
- X prettyprint_fn(1, av[i], n);
- X } else if (isbuiltin(av[i]) != NULL) {
- X f = TRUE;
- X for (j = 0; j < arraysize(builtins_str); j++)
- X if (streq(av[i], builtins_str[j]))
- X break;
- X fprint(1, "builtin %s\n", builtins_str[j]);
- X } else if ((e = which(av[i], FALSE)) != NULL) {
- X f = TRUE;
- X fprint(1, "%s\n", e);
- X }
- X if (!f) {
- X found = FALSE;
- X if (errno != ENOENT)
- X uerror(av[i]);
- X else
- X fprint(2, "%s not found\n", av[i]);
- X }
- X }
- X
- X set(found);
- }
- X
- /* push a string to be eval'ed onto the input stack. evaluate it */
- X
- static void b_eval(char **av) {
- X boolean i = interactive;
- X
- X if (av[1] == NULL)
- X return;
- X
- X interactive = FALSE;
- X pushinput(STRING, av + 1, i); /* don't reset line numbers on noninteractive eval */
- X doit(TRUE);
- X interactive = i;
- }
- X
- /*
- X push a file to be interpreted onto the input stack. with "-i" treat this as an interactive
- X input source.
- */
- X
- void b_dot(char **av) {
- X int fd;
- X boolean old_i = interactive, i = FALSE;
- X Estack e;
- X
- X av++;
- X
- X if (*av == NULL)
- X return;
- X
- X if (streq(*av,"-i")) {
- X av++;
- X i = TRUE;
- X }
- X
- X if (dasheye) { /* rc -i file has to do the right thing. reset the dasheye state to FALSE, though. */
- X dasheye = FALSE;
- X i = TRUE;
- X }
- X
- X if (*av == NULL)
- X return;
- X
- X fd = rc_open(*av, FROM);
- X
- X if (fd < 0) {
- X if (rcrc) /* on rc -l, don't flag nonexistence of .rcrc */
- X rcrc = FALSE;
- X else
- X uerror(*av);
- X set(FALSE);
- X return;
- X }
- X rcrc = FALSE;
- X
- X starassign(*av, av+1, TRUE);
- X pushinput(FD, fd);
- X interactive = i;
- X except(VARSTACK, "*", &e);
- X doit(TRUE);
- X varrm("*", TRUE);
- X unexcept(); /* VARSTACK */
- X interactive = old_i;
- }
- X
- /* Berkeley limit support was cleaned up by Paul Haahr. */
- X
- #ifdef NOLIMITS
- static void b_limit(char **av) {
- X rc_error("rc was compiled without berkeley limits");
- }
- #else
- X
- typedef struct Suffix Suffix;
- struct Suffix {
- X const Suffix *next;
- X long amount;
- X char *name;
- };
- X
- static const Suffix
- X kbsuf = { NULL, 1024, "k" },
- X mbsuf = { &kbsuf, 1024*1024, "m" },
- X gbsuf = { &mbsuf, 1024*1024*1024, "g" },
- X stsuf = { NULL, 1, "s" },
- X mtsuf = { &stsuf, 60, "m" },
- X htsuf = { &mtsuf, 60*60, "h" };
- #define SIZESUF &gbsuf
- #define TIMESUF &htsuf
- #define NOSUF ((Suffix *) NULL) /* for RLIMIT_NOFILE on SunOS 4.1 */
- X
- typedef struct {
- X char *name;
- X int flag;
- X const Suffix *suffix;
- } Limit;
- static const Limit limits[] = {
- X { "cputime", RLIMIT_CPU, TIMESUF },
- X { "filesize", RLIMIT_FSIZE, SIZESUF },
- X { "datasize", RLIMIT_DATA, SIZESUF },
- X { "stacksize", RLIMIT_STACK, SIZESUF },
- X { "coredumpsize", RLIMIT_CORE, SIZESUF },
- #ifdef RLIMIT_RSS /* SysVr4 does not have this */
- X { "memoryuse", RLIMIT_RSS, SIZESUF },
- #endif
- #ifdef RLIMIT_VMEM /* instead, they have this! */
- X { "vmemory", RLIMIT_VMEM, SIZESUF },
- #endif
- #ifdef RLIMIT_NOFILE /* SunOS 4.1 adds a limit on file descriptors */
- X { "descriptors", RLIMIT_NOFILE, NOSUF },
- #endif
- X { NULL, 0, NULL }
- };
- X
- extern int getrlimit(int, struct rlimit *);
- extern int setrlimit(int, struct rlimit *);
- X
- static void printlimit(const Limit *limit, boolean hard) {
- X struct rlimit rlim;
- X long lim;
- X getrlimit(limit->flag, &rlim);
- X if (hard)
- X lim = rlim.rlim_max;
- X else
- X lim = rlim.rlim_cur;
- X if (lim == RLIM_INFINITY)
- X fprint(1, "%s \tunlimited\n", limit->name);
- X else {
- X const Suffix *suf;
- X for (suf = limit->suffix; suf != NULL; suf = suf->next)
- X if (lim % suf->amount == 0) {
- X lim /= suf->amount;
- X break;
- X }
- X fprint(1, "%s \t%d%s\n", limit->name, lim, suf == NULL ? "" : suf->name);
- X }
- }
- X
- static long parselimit(const Limit *limit, char *s) {
- X int len = strlen(s);
- X long lim = 1;
- X const Suffix *suf = limit->suffix;
- X if (streq(s, "unlimited"))
- X return RLIM_INFINITY;
- X if (suf == TIMESUF && strchr(s, ':') != NULL) {
- X char *t = strchr(s, ':');
- X *t++ = '\0';
- X lim = 60 * a2u(s) + a2u(t);
- X } else {
- X for (; suf != NULL; suf = suf->next)
- X if (streq(suf->name, s + len - strlen(suf->name))) {
- X s[len - strlen(suf->name)] = '\0';
- X lim *= suf->amount;
- X break;
- X }
- X lim *= a2u(s);
- X }
- X return lim;
- }
- X
- static void b_limit(char **av) {
- X const Limit *lp = limits;
- X boolean hard = FALSE;
- X
- X if (*++av != NULL && streq(*av, "-h")) {
- X av++;
- X hard = TRUE;
- X }
- X
- X if (*av == NULL) {
- X for (; lp->name != NULL; lp++)
- X printlimit(lp, hard);
- X return;
- X }
- X
- X for (;; lp++) {
- X if (lp->name == NULL) {
- X fprint(2,"no such limit\n");
- X set(FALSE);
- X return;
- X }
- X if (streq(*av, lp->name))
- X break;
- X }
- X
- X if (*++av == NULL)
- X printlimit(lp, hard);
- X else {
- X struct rlimit rlim;
- X long pl;
- X getrlimit(lp->flag, &rlim);
- X if ((pl = parselimit(lp, *av)) < 0) {
- X fprint(2,"bad limit\n");
- X set(FALSE);
- X return;
- X }
- X if (hard)
- X rlim.rlim_max = pl;
- X else
- X rlim.rlim_cur = pl;
- X if (setrlimit(lp->flag, &rlim) == -1) {
- X uerror("setrlimit");
- X set(FALSE);
- X } else
- X set(TRUE);
- X }
- }
- #endif
- SHAR_EOF
- chmod 0644 builtins.c ||
- echo 'restore of builtins.c failed'
- Wc_c="`wc -c < 'builtins.c'`"
- test 11200 -eq "$Wc_c" ||
- echo 'builtins.c: original size 11200, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= builtins.h ==============
- if test -f 'builtins.h' -a X"$1" != X"-c"; then
- echo 'x - skipping builtins.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting builtins.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'builtins.h' &&
- typedef void builtin_t(char **);
- X
- extern builtin_t *isbuiltin(char *);
- extern void b_exec(char **), funcall(char **), b_dot(char **), b_builtin(char **);
- extern char *which(char *, boolean);
- SHAR_EOF
- chmod 0644 builtins.h ||
- echo 'restore of builtins.h failed'
- Wc_c="`wc -c < 'builtins.h'`"
- test 191 -eq "$Wc_c" ||
- echo 'builtins.h: original size 191, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= cfix.awk ==============
- if test -f 'cfix.awk' -a X"$1" != X"-c"; then
- echo 'x - skipping cfix.awk (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting cfix.awk (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'cfix.awk' &&
- BEGIN { Pending = 0; }
- #
- # Special cases. There are too many, but....
- #
- $0 == "static int (*realgchar)(void);" {
- X print "static int (*realgchar)();";
- X next;
- X }
- $0 == "static void (*realugchar)(int);" {
- X print "static void (*realugchar)();";
- X next;
- X }
- $0 == "static void b_break(char **), b_cd(char **)," {
- X print "static void b_break(), b_cd(),";
- X next;
- X }
- $0 == "\tb_echo(char **), b_eval(char **), b_exit(char **), b_limit(char **)," {
- X print "b_echo(), b_eval(), b_exit(), b_limit(),";
- X next;
- X }
- $0 == "\tb_return(char **), b_shift(char **), b_umask(char **), b_wait(char **)," {
- X print "b_return(), b_shift(), b_umask(), b_wait(),";
- X next;
- X }
- $0 == "\tb_whatis(char **);" {
- X print "b_whatis();";
- X next;
- X }
- $0 == "Node *treecpy(Node *s, void *(*alloc)(SIZE_T)) {" {
- X print "Node *treecpy(s, alloc)";
- X printf "Node *s;\nvoid *(*alloc)();\n{\n";
- X next;
- X }
- $0 == "\tvoid (*handler)(int);" {
- X print "\tvoid (*handler)();";
- X next;
- X }
- $0 == "\textern DIR *opendir(const char *);" {
- X print "#if 0";
- X print;
- X next;
- X }
- $0 == "\textern int closedir(DIR *);" {
- X print;
- X print "#endif";
- X next;
- X }
- $0 == "\textern int getopt(int, char **, char *);" {
- X print "\textern int getopt();";
- X next;
- X }
- $0 == "\tstatic void (*vectors[])(char *, List *, boolean) = {" {
- X print "\tstatic void (*vectors[])() = {";
- X next;
- X }
- $0 == "\t\tvoid (*handler)(int);" {
- X print "\t\tvoid (*handler)();";
- X next;
- X }
- $0 == "#include <stdarg.h>" {
- X print "#include <varargs.h>";
- X next;
- X }
- #
- # General cases.
- #
- /^static .*\);$/ {
- X n = split($0, tmp1, "(");
- X if (n != 2) {
- X print | "sh -c 'cat >&2'";
- X print "ERROR with left parens: ", n | "sh -c 'cat >&2'";
- X next;
- X }
- X printf "%s();\n", tmp1[1];
- X next;
- X }
- /^extern .*\);$/ {
- X n = split($0, tmp1, "(");
- X if (n != 2) {
- X print | "sh -c 'cat >&2'";
- X print "ERROR with left parens: ", n | "sh -c 'cat >&2'";
- X next;
- X }
- X printf "%s();\n", tmp1[1];
- X next;
- X }
- /^[a-zA-Z_][a-zA-Z_0-9]*:/ {
- X print;
- X next;
- X }
- /^[^ \t#][^(]*\([^)]*\.\.\.\).*{/ {
- X if (Pending != 0) {
- X print "ERROR: Pending != 0 on function entry" | "sh -c 'cat >&2'";
- X next;
- X }
- X n = split($0, tmp1, "(");
- X if (n != 2) {
- X print | "sh -c 'cat >&2'";
- X print "ERROR with left parens: ", n | "sh -c 'cat >&2'";
- X next;
- X }
- X n = split(tmp1[2], tmp2, ")");
- X if (n != 2) {
- X print | "sh -c 'cat >&2'";
- X print "ERROR with right parens: ", n | "sh -c 'cat >&2'";
- X next;
- X }
- X printf "%s(va_alist)\nva_dcl\n{\n", tmp1[1];
- X nargs = split(tmp2[1], args, ",");
- X for (i = 1; i <= nargs; i++) {
- X if (args[i] == "...") {
- X if (i == nargs) {
- X Pending = 1;
- X continue;
- X }
- X print "ERROR: ... isn't last argument", $0 | "sh -c 'cat >&2'";
- X next;
- X }
- X decls[i] = args[i] ";";
- X t = args[i];
- X for (;;) {
- X n = split(t, varname, " ");
- X if (n > 1) {
- X t = varname[n];
- X continue;
- X }
- X n = split(t, varname, "*");
- X if (n > 1) {
- X t = varname[n];
- X continue;
- X }
- X break;
- X }
- X type = substr(args[i], 1, length(args[i]) - length(t));
- X picks[i] = t " = va_arg(ap, " type ");"
- X
- X }
- X nargs--;
- X next;
- X }
- Pending == 1 && /va_list/ {
- X for (i = 1; i <= nargs; i++)
- X print decls[i];
- X }
- Pending == 1 && /va_start/ {
- X n = split($0, tmp1, ",");
- X if (n != 2) {
- X print "ERROR: bad va_start format" | "sh -c 'cat >&2'";
- X next;
- X }
- X printf "%s);\n", tmp1[1];
- X for (i = 1; i <= nargs; i++)
- X print picks[i];
- X Pending = 0;
- X next;
- X }
- /^[^ \t#][^(]*\([^)]*\).*{/ {
- X if (Pending != 0) {
- X print "ERROR: Pending != 0 on function entry" | "sh -c 'cat >&2'";
- X next;
- X }
- X n = split($0, tmp1, "(");
- X if (n != 2) {
- X print | "sh -c 'cat >&2'";
- X print "ERROR with left parens: ", n | "sh -c 'cat >&2'";
- X next;
- X }
- X n = split(tmp1[2], tmp2, ")");
- X if (n != 2) {
- X print | "sh -c 'cat >&2'";
- X print "ERROR with right parens: ", n | "sh -c 'cat >&2'";
- X next;
- X }
- # if (tmp2[2] != " {") {
- # print "ERROR with last component: `", tmp2[2], "'";
- # next;
- # }
- X if (tmp2[1] ~ /^[ \t]*void[ \t]*$/ || tmp2[1] ~ /^[ \t]*$/) {
- X # no arguments
- X printf "%s() {\n\n", tmp1[1];
- X next;
- X }
- X printf "%s(", tmp1[1];
- X needcomma = 0;
- X nargs = split(tmp2[1], args, ",");
- X for (i = 1; i <= nargs; i++) {
- X if (args[i] == "...") {
- X print "ERROR: ... shouldn't get here", $0 | "sh -c 'cat >&2'";
- X next;
- X }
- X decls[i] = args[i] ";";
- X if (needcomma)
- X printf ", ";
- X needcomma = 1;
- X t = args[i];
- X if (t ~ /\[\]$/)
- X t = substr(t, 1, length(t) - 2);
- X for (;;) {
- X n = split(t, varname, " ");
- X if (n > 1) {
- X t = varname[n];
- X continue;
- X }
- X n = split(t, varname, "*");
- X if (n > 1) {
- X t = varname[n];
- X continue;
- X }
- X break;
- X }
- X printf "%s", varname[n];
- X }
- X print ")";
- X for (i = 1; i <= nargs; i++)
- X print decls[i];
- X print "{";
- X next;
- X }
- #
- # If we didn't match at all, the line doesn't change.
- #
- X { print; }
- SHAR_EOF
- chmod 0644 cfix.awk ||
- echo 'restore of cfix.awk failed'
- Wc_c="`wc -c < 'cfix.awk'`"
- test 5252 -eq "$Wc_c" ||
- echo 'cfix.awk: original size 5252, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= config.h ==============
- if test -f 'config.h' -a X"$1" != X"-c"; then
- echo 'x - skipping config.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting config.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'config.h' &&
- /*
- X * Suggested settings for Sun, NeXT and sgi (machines here at TAMU):
- X */
- X
- #ifdef NeXT
- #define NODIRENT
- #define PROTECT_ENV
- #define PROTECT_JOB
- #define NOCMDARG
- #endif
- X
- #ifdef sgi
- #define NOSIGCLD
- #define PROTECT_ENV
- #endif
- X
- #ifdef sun
- #define PROTECT_ENV
- #endif
- X
- /*
- X * Suggested settings for HP300 running 4.3BSD-utah (DWS):
- X */
- X
- #if defined(hp300) && !defined(hpux)
- #define NODIRENT
- #define NOCMDARG
- #define DEFAULTINTERP "/bin/sh"
- #define PROTECT_ENV
- #endif
- X
- /*
- X * Suggested settings for Ultrix
- X */
- X
- #ifdef ultrix
- #define PROTECT_ENV
- #endif
- SHAR_EOF
- chmod 0644 config.h ||
- echo 'restore of config.h failed'
- Wc_c="`wc -c < 'config.h'`"
- test 546 -eq "$Wc_c" ||
- echo 'config.h: original size 546, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= except.c ==============
- if test -f 'except.c' -a X"$1" != X"-c"; then
- echo 'x - skipping except.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting except.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'except.c' &&
- #include "jbwrap.h"
- #include <stdarg.h>
- #include "rc.h"
- #include "utils.h"
- #include "except.h"
- #include "status.h"
- #include "hash.h"
- #include "input.h"
- #include "nalloc.h"
- X
- /*
- X a return goes back stack frames to the last return. A break does not. A signal
- X goes to the last interactive level.
- */
- X
- static Estack *estack;
- X
- /* add an exception to the input stack. */
- X
- void except(enum except e, void *jb, Estack *ex) {
- X ex->prev = estack;
- X estack = ex;
- X
- X switch (estack->e = e) {
- X case ARENA:
- X estack->b = newblock();
- X break;
- X case ERROR:
- X case BREAK:
- X case RETURN:
- X estack->interactive = interactive;
- X estack->jb = (jbwrap *) jb;
- X break;
- X case VARSTACK:
- X estack->name = (char *) jb;
- X break;
- X }
- }
- X
- /* remove an exception, restore last interactive value */
- X
- void unexcept() {
- X if (estack->e == ERROR)
- X interactive = estack->interactive;
- X else if (estack->e == ARENA)
- X restoreblock(estack->b);
- X estack = estack->prev;
- }
- X
- /*
- X Raise an exception. The rules are pretty complicated: you can return from a loop inside a
- X function, but you can't break from a function inside of a loop. On errors, rc_raise() goes back
- X to the LAST INTERACTIVE stack frame. If no such frame exists, then rc_raise() exits the shell.
- X This is what happens, say, when there is a syntax error in a noninteractive shell script. While
- X traversing the exception stack backwards, rc_raise() also removes input sources (closing
- X file-descriptors, etc.) and pops instances of $* that have been pushed onto the variable stack
- X (e.g., for a function call).
- */
- X
- void rc_raise(enum except e) {
- X if (e == ERROR && rc_pid != getpid())
- X exit(1); /* child processes exit on an error/signal */
- X
- X for (; estack != NULL; estack = estack->prev)
- X if (estack->e != e) {
- X if (e == BREAK && estack->e != ARENA)
- X rc_error("break outside of loop");
- X else if (e == RETURN && estack->e == ERROR) /* can return from loops inside functions */
- X rc_error("return outside of function");
- X if (estack->e == VARSTACK)
- X varrm(estack->name, TRUE);
- X else if (estack->e == ARENA)
- X restoreblock(estack->b);
- X } else {
- X if (e == ERROR && !estack->interactive) {
- X popinput();
- X } else {
- X jbwrap *j = estack->jb;
- X
- X interactive = estack->interactive;
- X estack = estack->prev;
- X longjmp(j->j, 1);
- X }
- X }
- X rc_exit(1); /* top of exception stack */
- }
- SHAR_EOF
- chmod 0644 except.c ||
- echo 'restore of except.c failed'
- Wc_c="`wc -c < 'except.c'`"
- test 2339 -eq "$Wc_c" ||
- echo 'except.c: original size 2339, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= except.h ==============
- if test -f 'except.h' -a X"$1" != X"-c"; then
- echo 'x - skipping except.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting except.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'except.h' &&
- enum except { ERROR, BREAK, RETURN, VARSTACK, ARENA };
- typedef struct Estack Estack;
- X
- struct Estack {
- X enum except e;
- X boolean interactive;
- X jbwrap *jb;
- X Block *b;
- X char *name;
- X Estack *prev;
- };
- X
- extern void rc_raise(enum except);
- extern void except(enum except, void *, Estack *);
- extern void unexcept(void);
- SHAR_EOF
- chmod 0644 except.h ||
- echo 'restore of except.h failed'
- Wc_c="`wc -c < 'except.h'`"
- test 310 -eq "$Wc_c" ||
- echo 'except.h: original size 310, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= exec.c ==============
- if test -f 'exec.c' -a X"$1" != X"-c"; then
- echo 'x - skipping exec.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting exec.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'exec.c' &&
- /*
- X exec.c: exec() takes an argument list and does the appropriate thing
- X (calls a builtin, calls a function, etc.)
- */
- X
- #include <signal.h>
- #include <errno.h>
- #include "rc.h"
- #include "utils.h"
- #include "exec.h"
- #include "status.h"
- #include "hash.h"
- #include "builtins.h"
- #include "footobar.h"
- #include "jbwrap.h"
- #include "except.h"
- #include "redir.h"
- #include "wait.h"
- X
- void exec(List *s, boolean parent) {
- X char **av, **ev;
- X int pid, stat;
- X builtin_t *b;
- X char *path = NULL;
- X void (*handler)(int);
- X boolean forked, saw_exec, saw_builtin;
- X
- X av = list2array(s, dashex);
- X ev = makeenv();
- X saw_builtin = saw_exec = FALSE;
- X
- X do {
- X if (*av == NULL || isabsolute(*av))
- X b = NULL;
- X else if (!saw_builtin && fnlookup(*av) != NULL)
- X b = funcall;
- X else
- X b = isbuiltin(*av);
- X
- X saw_builtin = FALSE; /* a builtin applies only to the immmediately following command, e.g., builtin exec echo hi */
- X
- X if (b == b_exec) {
- X av++;
- X saw_exec = TRUE;
- X parent = FALSE;
- X } else if (b == b_builtin) {
- X av++;
- X saw_builtin = TRUE;
- X }
- X } while (b == b_exec || b == b_builtin);
- X
- X if (*av == NULL && saw_exec) { /* do redirs and return on a null exec */
- X doredirs();
- X return;
- X }
- X
- X if (b == NULL) {
- X path = which(*av, TRUE);
- X if (path == NULL && *av != NULL) { /* perform null commands for redirections */
- X set(FALSE);
- X redirq = NULL;
- X empty_fifoq();
- X if (parent)
- X return;
- X rc_exit(1);
- X }
- X }
- X
- X /* if parent & the redirq is nonnull, builtin or not it has to fork. */
- X
- X if (parent && (b == NULL || redirq != NULL)) {
- X pid = rc_fork();
- X forked = TRUE;
- X } else {
- X pid = 0;
- X forked = FALSE;
- X }
- X
- X switch (pid) {
- X case -1:
- X uerror("fork");
- X rc_error(NULL);
- X /* NOTREACHED */
- X case 0:
- X if (forked)
- X setsigdefaults();
- X doredirs();
- X
- X /* null commands performed for redirections */
- X if (*av == NULL || b != NULL) {
- X if (b != NULL)
- X b(av);
- X empty_fifoq();
- X if (!forked && parent)
- X return;
- X rc_exit(getstatus());
- X }
- #ifdef NOEXECVE
- X my_execve(path, (const char **) av, (const char **) ev); /* bogus, huh? */
- #else
- X execve(path, (const char **) av, (const char **) ev);
- #endif
- #ifdef DEFAULTINTERP
- X if (errno == ENOEXEC) {
- X *av = path;
- X *--av = DEFAULTINTERP;
- X execve(*av, (const char **) av, (const char **) ev);
- X }
- #endif
- X uerror(*av);
- X rc_exit(1);
- X /* NOTREACHED */
- X default:
- X if ((handler = signal(SIGINT, SIG_IGN)) != sig)
- X signal(SIGINT, handler); /* don't ignore interrupts in noninteractive mode */
- X rc_wait4(pid, &stat);
- X signal(SIGINT, handler);
- X redirq = NULL;
- X empty_fifoq();
- X setstatus(stat);
- X if (stat == SIGINT || stat == SIGQUIT) /* interrupted? let the handler deal with it. */
- X rc_raise(ERROR);
- X }
- }
- SHAR_EOF
- chmod 0644 exec.c ||
- echo 'restore of exec.c failed'
- Wc_c="`wc -c < 'exec.c'`"
- test 2671 -eq "$Wc_c" ||
- echo 'exec.c: original size 2671, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= exec.h ==============
- if test -f 'exec.h' -a X"$1" != X"-c"; then
- echo 'x - skipping exec.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting exec.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'exec.h' &&
- struct Rq {
- X Node *r;
- X struct Rq *n;
- };
- X
- extern void exec(List *, boolean);
- extern void doredirs(void);
- SHAR_EOF
- chmod 0644 exec.h ||
- echo 'restore of exec.h failed'
- Wc_c="`wc -c < 'exec.h'`"
- test 104 -eq "$Wc_c" ||
- echo 'exec.h: original size 104, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= execve.c ==============
- if test -f 'execve.c' -a X"$1" != X"-c"; then
- echo 'x - skipping execve.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting execve.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'execve.c' &&
- /* execve.c: an execve() for geriatric unices without #! */
- SHAR_EOF
- true || echo 'restore of execve.c failed'
- fi
- echo 'End of part 1'
- echo 'File execve.c is continued in part 2'
- echo 2 > _shar_seq_.tmp
- exit 0
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-